package com.hundsun.utils;

import com.hundsun.model.MappingConfigInfo;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author jiangwj20966 2018/9/21
 */
public class ExcelToDbConfigParser {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private final String TAG_CONFIG_ROOT = "configs";
    private final String TAG_TABLE_MAPPING = "tableMapping";
    private final String TAG_COLUMN = "column";


    private final String ATTR_TABLE_NAME = "tableName";
    private final String ATTR_EXCEL_FILE_NAME = "excelFileName";
    private final String ATTR_COLUMN_NAME = "columnName";
    private final String ATTR_EXCEL_COLUMN_INDEX = "excelColumnIndex";

    private Map<String, MappingConfigInfo> mappingConfigInfos;

    private boolean correctInitialized = false;

    public static ExcelToDbConfigParser getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private static class InstanceHolder {
        private static ExcelToDbConfigParser INSTANCE = new ExcelToDbConfigParser();
    }

    private ExcelToDbConfigParser() {
        init();
    }

    private void init() {
        InputStream configFileInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("excel_to_dbtable_config.xml");
        SAXReader saxReader = new SAXReader();
        correctInitialized = false;
        try {
            Document document = saxReader.read(configFileInputStream);
            Element root = document.getRootElement();
            List<Element> tableMappingList = root.elements(TAG_TABLE_MAPPING);
            mappingConfigInfos = new ConcurrentHashMap<>();
            if (tableMappingList != null && tableMappingList.size() > 0) {
                MappingConfigInfo configInfo;
                for (Element mappingElement : tableMappingList) {
                    configInfo = new MappingConfigInfo();

                    configInfo.setTableName(mappingElement.attributeValue(ATTR_TABLE_NAME));
                    configInfo.setExcelFileName(mappingElement.attributeValue(ATTR_EXCEL_FILE_NAME));

                    List<Element> columnElements = mappingElement.elements(TAG_COLUMN);
                    if (columnElements != null && columnElements.size() > 0) {
                        for (Element columnElement : columnElements) {
                            configInfo.addColumnInfo(
                                    new MappingConfigInfo.ColumnInfo(
                                            columnElement.attributeValue(ATTR_COLUMN_NAME),
                                            columnElement.attributeValue(ATTR_EXCEL_COLUMN_INDEX)
                                    )
                            );
                        }
                    } else {
                        throw new IllegalArgumentException(configInfo.getTableName() + "的表字段配置信息为空");
                    }
                    mappingConfigInfos.put(configInfo.getExcelFileName(), configInfo);
                }
                correctInitialized = true;
            }
        } catch (DocumentException e) {
            logger.error("读取配置文件失败", e);
        } catch (IllegalArgumentException e) {
            logger.error("配置文件内容错误，请检查", e);
        }
    }

    /**
     * 根据Excel名称唯一性获取到对应Excel名字的配置信息
     *
     * @param excelFileName Excel名
     * @return {@see com.hundsun.model.MappingConfigInfo} 返回配置信息，包含表名，表字段和数据映射信息等
     */
    public MappingConfigInfo getMappingConfigByExcelFile(String excelFileName) {
        if (correctInitialized) {
            return mappingConfigInfos.get(excelFileName);
        } else {
            throw new IllegalStateException("配置信息未正确初始化");
        }
    }

    public static void main(String[] args) {
        System.out.println(GsonFormatUtil.prettyJsonString(ExcelToDbConfigParser.getInstance().getMappingConfigByExcelFile("DEMO").toString()));
    }
}
